#ifndef BPIO_H
#define BPIO_H 1

#define _FILE_OFFSET_BITS  64

#include <stdio.h>
#include <pthread.h>
#ifdef WIN32
	#include <io.h>
	#include <wchar.h>
//	#include <process.h>
//	#include <windows.h> 
    #define off_t __int64
#else
	#include <unistd.h>
#endif
#include <fcntl.h>

typedef struct bpbuf_s bpbuf_t;

typedef struct bpio_s {
    int nfillers;	/* readers read from disk -> bufs */
    bpbuf_t *bpb;	/* bpb[reader(0..nfillers-1)] */
    int bufsize;	/* matching that of bpb->bufsize */
    int readsize;	/* ditto */
    int drain;		/* next bpbuf_t to drain (dynamic, but owned by drain thread) */
    int fwd;		/* bpb->incrpos = fwd * nfillers * bufsize */

} bpio_t;

/* Is someone waiting on our condition-variable?  Why? */
enum business { NO, EMPTY, FULL, PAUSED };

struct bpbuf_s {
    		/* Static stuff */
    bpio_t 	  *bpio;
    int     	  nbufs;	/* number of buffers per reader */
    int	    	  bufsize;
    int		  readsize;
    unsigned char *bufspace;
    unsigned char **bufs;	/* page-aligned buffers  bufs[0..nbufs-1] */
    int		  bpbno;	/* our index in parent */
    int		  fd;		/* file descriptor */

    volatile off_t *curpos;	/* curpos[0..nbufs-1] -- filepos whence read */
    volatile off_t wrappos;	/* wrap back to poswrap after passing EOF */
    volatile off_t eofpos;	/* here's the nominal EOF point */
    volatile off_t incrpos;	/* increment from one read to the next */
    volatile int  doloop;	/* automatically loop at EOF? */

    		/* Dynamic stuff, held under locks */
    volatile int     fillwaiting; /* is filler waiting? */
    volatile int     drainwaiting; /* is drainer waiting? */
    volatile int     filling;	/* is filler thread supposed to be running? */
    volatile int     busy;	/* is filler busy reading? (if "filling" was cleared, has it noticed?) */

    volatile off_t	filepos;/* file offset for next buffer to be filled*/
    volatile int	wp;	/* next-buffer-to-be-drained (to display) index */
    volatile int	rp;	/* next-buffer-to-be-filled (from file) index */

    pthread_t	     bthread;
    pthread_mutex_t  bmut;
    pthread_cond_t   bfillwait;	/* filler waiting (due to not-yet-setup or full queue)? */
    pthread_cond_t   bdrainwait; /* drainer wait (due to empty queue)? */

};

extern void bpclose( bpio_t *bpio );
extern int bpopen( bpio_t *bpio, char *fname );
extern int bpbfull( bpbuf_t *bpb );
extern int bpbempty( bpbuf_t *bpb );
extern bpio_t *bpinit( bpio_t *bpio, int nfillers, int bufsize, int readsize, int nbufseach );
extern void bpseek( bpio_t *bpio, off_t pos );
extern unsigned char *bpcurbuf( bpio_t *bpio );
extern off_t bptell( bpio_t *bpio );
extern void bpstart( bpio_t *bpio, int wrap );
extern void bpstop( bpio_t *bpio );
extern void bpforward( bpio_t *bpio, int fwd );
extern void bprange( bpio_t *bpio, off_t from, off_t to );

extern void *bpfiller( void *vbpb );
extern int  bpdrain( bpio_t *bpio, int (*sink)( unsigned char *buf, int nbytes, void *arg ), void *arg );
extern void bpsync( bpio_t *bpio );
extern int get_pagesize();

#ifdef WIN32
	extern void usleep( int us );
#endif

#endif
